package frame.util;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

// 可变引用类
public final class Ref<T> {
	
	private T value;

	private Ref() {

    }

    private Ref(final T value) {
		
		this.value = value;
	}

	public static <T> Ref<T> of(final T value) {

	    return new Ref<>(value);
    }

    public static <T> Ref<T> empty() {

	    return Ref.of(null);
    }

	public Ref<T> swap(final T value) {
		
		this.value = value;
		
		return this;
	}
	
	public Ref<T> shift(final T value) {
		
		final Ref<T> old = Ref.of(this.value);
		
		swap(value);
		
		return old;
	}

	public <R> Ref<R> map(final Function<T, R> trans) {

		return isPresent() ? Ref.of(trans.apply(value)) : Ref.of(null);
	}

	public <R> Ref<R> flatMap(final Function<T, Ref<R>> trans) {

        return isPresent() ? trans.apply(value) : empty();
	}

	public boolean isPresent() {

		return value != null;
	}

	public void ifPresent(final Consumer<T> consumer) {
		
		if(isPresent()) consumer.accept(get());
	}

	public T get() {

		return value;
	}

	public T orElse(final T elseValue) {

		return isPresent() ? get() : elseValue;
	}

	public T orElseGet(final Supplier<T> supplier) {

	    return isPresent() ? get() : supplier.get();
    }

    public <X extends Throwable> T orElseThrow(final Supplier<? extends X> exceptionSupplier) throws X {

	    if(isPresent()) return get(); else throw exceptionSupplier.get();
    }
}
